import Commander
import Foundation
import PeekabooCore
import PeekabooFoundation

/// Press individual keys or key sequences
@available(macOS 14.0, *)
@MainActor
struct PressCommand: ErrorHandlingCommand, OutputFormattable {
    @Argument(help: "Key(s) to press")
    var keys: [String]

    @Option(help: "Repeat count for all keys")
    var count: Int = 1

    @Option(help: "Delay between key presses in milliseconds")
    var delay: Int = 100

    @Option(help: "Hold duration for each key in milliseconds")
    var hold: Int = 50

    @Option(help: "Session ID (uses latest if not specified)")
    var session: String?

    @OptionGroup var focusOptions: FocusCommandOptions
    @RuntimeStorage private var runtime: CommandRuntime?

    private var resolvedRuntime: CommandRuntime {
        guard let runtime else {
            preconditionFailure("CommandRuntime must be configured before accessing runtime resources")
        }
        return runtime
    }

    private var services: any PeekabooServiceProviding { self.resolvedRuntime.services }
    private var logger: Logger { self.resolvedRuntime.logger }
    var outputLogger: Logger { self.logger }
    var jsonOutput: Bool { self.resolvedRuntime.configuration.jsonOutput }

    @MainActor
    mutating func run(using runtime: CommandRuntime) async throws {
        self.runtime = runtime
        let startTime = Date()
        self.logger.setJsonOutputMode(self.jsonOutput)

        do {
            try self.validate()
            // Get session if available
            let sessionId: String? = if let providedSession = session {
                providedSession
            } else {
                await self.services.sessions.getMostRecentSession()
            }

            // Ensure window is focused before pressing keys
            if let sessionId {
                try await ensureFocused(
                    sessionId: sessionId,
                    options: self.focusOptions,
                    services: self.services
                )
            }

            // Build actions - repeat each key sequence 'count' times
            var actions: [TypeAction] = []
            for _ in 0..<self.count {
                for (index, key) in self.keys.indexed() {
                    if let specialKey = SpecialKey(rawValue: key.lowercased()) {
                        actions.append(.key(specialKey))
                    }

                    // Add delay between keys (but not after the last key of the last repetition)
                    let isLastKey = index == self.keys.count - 1
                    let isLastRepetition = self.count == 1
                    if !isLastKey || !isLastRepetition {
                        // We'll handle the delay in the service
                    }
                }
            }

            // Execute key presses
            let typeRequest = TypeActionsRequest(
                actions: actions,
                cadence: .fixed(milliseconds: self.delay),
                sessionId: sessionId
            )
            let result = try await AutomationServiceBridge.typeActions(
                automation: self.services.automation,
                request: typeRequest
            )

            // Output results
            let pressResult = PressResult(
                success: true,
                keys: keys,
                totalPresses: result.keyPresses,
                count: self.count,
                executionTime: Date().timeIntervalSince(startTime)
            )

            output(pressResult) {
                print("✅ Key press completed")
                print("🔑 Keys: \(self.keys.joined(separator: " → "))")
                if self.count > 1 {
                    print("🔢 Repeated: \(self.count) times")
                }
                print("📊 Total presses: \(result.keyPresses)")
                print("⏱️  Completed in \(String(format: "%.2f", Date().timeIntervalSince(startTime)))s")
            }

        } catch {
            self.handleError(error)
            throw ExitCode.failure
        }
    }

    // Error handling is provided by ErrorHandlingCommand protocol

    mutating func validate() throws {
        for key in self.keys {
            guard SpecialKey(rawValue: key.lowercased()) != nil else {
                throw ValidationError("Unknown key: '\(key)'. Run 'peekaboo press --help' for available keys.")
            }
        }
    }
}

// MARK: - JSON Output Structure

struct PressResult: Codable {
    let success: Bool
    let keys: [String]
    let totalPresses: Int
    let count: Int
    let executionTime: TimeInterval
}

// MARK: - Conformances

@MainActor
extension PressCommand: ParsableCommand {
    nonisolated(unsafe) static var commandDescription: CommandDescription {
        MainActorCommandDescription.describe {
            CommandDescription(
                commandName: "press",
                abstract: "Press individual keys or key sequences",
                discussion: """
                    The 'press' command sends individual key presses or sequences.
                    It's designed for special keys and navigation, not for typing text.

                    EXAMPLES:
                      peekaboo press return                # Press Enter/Return
                      peekaboo press tab --count 3         # Press Tab 3 times
                      peekaboo press escape                # Press Escape
                      peekaboo press delete                # Press Backspace/Delete
                      peekaboo press forward_delete        # Press Forward Delete (fn+delete)
                      peekaboo press up down left right    # Arrow key sequence
                      peekaboo press f1                    # Press F1 function key
                      peekaboo press space                 # Press spacebar
                      peekaboo press enter                 # Numeric keypad Enter

                    AVAILABLE KEYS:
                      Navigation: up, down, left, right, home, end, pageup, pagedown
                      Editing: delete (backspace), forward_delete, clear
                      Control: return, enter, tab, escape, space
                      Function: f1-f12
                      Special: caps_lock, help

                    KEY SEQUENCES:
                      Multiple keys can be pressed in sequence with optional delay:
                      peekaboo press tab tab return        # Tab twice then Enter
                      peekaboo press down down return      # Navigate down and select

                    TIMING:
                      Use --delay to control timing between key presses (default: 100ms)
                      Use --hold to control how long each key is held (default: 50ms)
                """,

                showHelpOnEmptyInvocation: true
            )
        }
    }
}

extension PressCommand: AsyncRuntimeCommand {}

@MainActor
extension PressCommand: CommanderBindableCommand {
    mutating func applyCommanderValues(_ values: CommanderBindableValues) throws {
        guard !values.positional.isEmpty else {
            throw CommanderBindingError.missingArgument(label: "keys")
        }
        self.keys = values.positional
        if let count: Int = try values.decodeOption("count", as: Int.self) {
            self.count = count
        }
        if let delay: Int = try values.decodeOption("delay", as: Int.self) {
            self.delay = delay
        }
        if let hold: Int = try values.decodeOption("hold", as: Int.self) {
            self.hold = hold
        }
        self.session = values.singleOption("session")
        self.focusOptions = try values.makeFocusOptions()
    }
}
